#!/usr/bin/python
# -*- coding: utf-8 -*-
import xmpp
import time, os, sys, re, urllib
import Queue
import logging
import socket
from threading import Thread
from datetime import datetime
from config import *
from cgi import escape
from modules.daemon import Daemon


logging.basicConfig(filename=LOG_FILE,level=logging.DEBUG)

class JBotSocketListener(Thread):
    def __init__(self, q):
        Thread.__init__(self)
        self.socket_file = MESSAGE_SOCKET
        self.q = q

    def open_socket(self):
        logging.info('opening socket {0}'.format(self.socket_file))
        self.socket = socket.socket(socket.AF_UNIX) # создаём сокет домена AF_UNIX
        self.socket.bind(self.socket_file)          # привязываем его к файлу
    def close_socket(self):
        self.socket.close()
    def listen(self):
        logging.info('listening socket')
        self.socket.listen(5)                       # начинаем прослушивать
        logging.info('waiting for connection')
        # conn.send('HELO')               
        while 1:
            conn, addr = self.socket.accept()           # ждём подключения
            data = conn.recv(1024)        # получаем от клиента данные
            if data:
                logging.info('recieved {0} bytes from socket: '.format(len(data), data) )
                print data
                self.q.put(data)

    def run(self):
        try: os.remove(MESSAGE_SOCKET)
        except: pass

        logging.info('Starting socket listener')
        self.open_socket()
        self.listen()

class JBot(Daemon):
    def __init__(self, *args, **kwargs):
        Daemon.__init__(self, *args, **kwargs)
        self.messages_queue = Queue.Queue()
        self.nick = BOT_NICK
    def send_to_conference(self, text):
        """ send text to conference room """
        if text:
            try:
                text = text.strip()#.encode('utf-8')
                message=xmpp.Message(CONF[0],text)
                message.setAttr('type', 'groupchat')
                self.connection.send(message)
            except Exception as e:
                print >> sys.stderr, "sendToChat error:", e
                logging.warning('send_to_conference error: {0}'.format(e))
                jsendConf(u"Ой.. "+str(e)+"\n"+u"То есть "+text)

    def send_to_user(self, jid, text):
        """ send text to specified jid """
        if jid and text:
            try:
                text = text.strip()#.encode('utf-8')
                message=xmpp.Message(jid, text)
                message.setAttr('type', 'chat')
                self.connection.send(message)
            except Exception as e:
                print >> sys.stderr, "sendToChat error:", e
                logging.warning('send_to_conference error: {0}'.format(e))
                jsendConf(u"Ой.. "+str(e)+"\n"+u"То есть "+text)


    def messageCB(self, connection, mess): #обработчик сообщений
        """ incoming messages handler """
        self.messageCounter+=1
        self.connection=connection
        # logging.debug(u'got message. getFrom: {0}, text: {1}'.format(mess.getFrom(), mess.getBody() ) )
        mess_type=mess.getType()
        text=mess.getBody()
        if mess_type == 'groupchat':
            nick=mess.getFrom().getResource()
            if nick!=self.nick: self.process_conf_message(nick, text)
        elif mess_type == 'chat':
            from_user = mess.getFrom()
            self.process_incoming_message(from_user, text)
        elif mess_type == 'error':
            logging.warning(u'got error message: {0}'.format(text))
        else:
            logging.warning('got {0} message. What should I do?'.format(mess_type))

    def presenceCB(self, connection, pres): #обработчик изменений ростера
        """ presence changes handler """
        self.messageCounter+=1
        nick=pres.getFrom().getResource()
        text=''
        if pres.getType()=='unavailable':
            if nick in self.roster:
                text=nick+u' покинул конференцию'
                self.roster.remove(nick)
                logging.info(text)
        else:
            if nick not in self.roster:
                text=nick+u' зашел в конференцию'
                self.roster.append(nick)
                logging.info(text)
        if text:
            self.log_conference_message(nick,text)

    def send_from_file(self):
        """ send text from MESSAGE_FILE to conference """
        text=u''
        try:
            lines=open(MESSAGE_FILE,'r').readlines()
            if len(lines): log.debug('send_from_file: read {0} lines from message file'.format(len(lines)))
            for line in lines:
                line = f.readline()
                try: line=unicode(line, 'utf-8')
                except:
                    print >>sys.stderr, "sendFromFile error: file read, but lines not encoded..."
                    logging.warning('send_from_file: line not encoded')
                if (len(line.strip('\n'))): text+=line+"\n"

        except Exception as e:
            print >> sys.stderr, "sendFromFile error:", e
        if len(text):
            logging.info( 'got {0} bytes from message file'.format(len(text)) )
            self.send_to_conference(text)
            f=open(MESSAGE_FILE,'w')
            f.close()

    def log_conference_message(self, nick, text):
        """ save message to conference log file """
        timeId=str(int(time.time()))+str(self.messageCounter)
        line=u"#%s %s %s> %s"%(timeId, time.strftime("%d.%m.%Y %H:%M:%S"),nick,text)
        line=line.encode('utf-8')
        logging.info('logging message from chat')
        try:
            f=open(CHAT_LOG_FILE,"a")
            f.write(line+"\n")
            f.close()
        except: pass

    def process_conf_message(self, nick, text, **kwargs):
        """ decide what to to with message from conference """
        self.log_conference_message(nick, text)
        if text and not nick==BOT_NICK:
            logging.info(u'See groupchat message from {0}: {1}'.format(nick, text))

    def process_incoming_message(self, from_user, text):
        """ decide what to to with direct message """
        logging.info(u'Got message from {0}: {1}'.format(from_user, text) )
        pass
    def process_task(self, msg):
        logging.warning('original process_task called. it must be redefined!')
        self.send_to_conference(msg)


    def check_queue(self):
        """ looking for tasks in queue end send them to conference """
        if not self.messages_queue.empty():
            logging.debug(u'got {0} tasks in messages queue'.format(self.messages_queue.qsize()) )
            while not self.messages_queue.empty():
                msg = self.messages_queue.get()
                self.messages_queue.task_done()
                self.process_task(msg)
                logging.debug('task_done. {0} left'.format(self.messages_queue.qsize()) )


    def process_loop(self):
        """ tasks to do in loop """
        if (time.time()-self.timer)>3:
            self.send_from_file()
            self.check_queue()
            self.timer=time.time()
        self.connection.Process(1)

    def run(self):
        print "---- ikitobot start! ----"
        logging.info("----- jbot start! -----")
        self.messageCounter=0
        
        socket_listener = JBotSocketListener(self.messages_queue)
        socket_listener.start()

        self.roster=[]
        self.connection=xmpp.Client(xmpp.JID(BOT[0]).getDomain(),debug=[])

        logging.info('connecting')

        self.connection.connect(proxy=PROXY)
        self.connection.RegisterHandler('message',self.messageCB)
        self.connection.RegisterHandler('presence',self.presenceCB)

        logging.info('authorization')

        auth = self.connection.auth(xmpp.JID(BOT[0]).getNode(),BOT[1])
        if not auth:
            logging.critical('unable to perform auth!')
            exit(0)

        logging.info('entering to conference {0}'.format(CONF[0]))

        conf_presence=xmpp.Presence(to='%s/%s'%(CONF[0], self.nick))
        conf_presence.setTag('x',namespace=xmpp.NS_MUC).setTagData('password',CONF[1])
        conf_presence.getTag('x').addChild('history',{'maxchars':'0','maxstanzas':'0'})
        
        presence = xmpp.Presence(status = "Ready!", show ="chat", priority = '1')
        self.connection.send(presence)
        self.connection.send(conf_presence)

        self.start_time=time.time()
        self.timer = time.time()
        print "------ bot started ------"
        logging.info('bot started!')
        self.send_to_conference(u'Я пришел!')
        self.send_from_file()

        logging.info('starting socket listener thread')
        
        
        logging.info('processing loop')
        while 1:
            self.process_loop()

def send_to_chat(text, repeat=True):
    import socket
    from time import sleep
    for i in range(5):
        try:
            c = socket.socket(socket.AF_UNIX)
            print "connecting to socket "+MESSAGE_SOCKET
            c.connect(MESSAGE_SOCKET)       # подключаемся к сокету сервера
            print "sending message"
            c.send(text)          # отправляем свои данные
            print "close socket"
            sleep(1)
            c.close()                         # закрываем соединение
            return
        except socket.error:
            sleep(2)
            if repeat: return send_to_chat(text, False)

